/*
 * RecordDownloader.cpp
 *
 *  Created on: 2018年8月9日
 *      Author: zhengboyuan
 */
#include "stdafx.h"
#include "RecordDownloader.h"
#include "TFileUtil.h"
#include "CLog.h"

RecordDownloader::RecordDownloader():
	m_system(),
	m_stream(),
	m_record(),
	m_format(),
	m_formatReady(),
	m_handle(),
	m_sink(),
	m_bytes(),
	m_time()
{
}

RecordDownloader::~RecordDownloader()
{
	close();
}

bool RecordDownloader::open(nvs::NetVideoSystem* system, const nvs::RecordItem& rec, const char* filepath)
{
	if (!system)
	{
		return false;
	}

	m_system = system;
	//m_record = rec;
	memcpy(&m_record, &rec, sizeof(rec));
	m_filepath = filepath;
	
	nvs::MediaStream* stream = NULL;
	int ret = m_system->openRecordStream(rec, &m_stream);
	if (ret != nvs::NVS_ERR_OK)
	{
		return false;
	}

	int rc = m_stream->getFormat(m_format);
	if (rc == 0)
	{
		m_formatReady = true;
		openStream(m_format);
	}

	m_stream->setSink(this);

	m_stream->setScale(100.0);

	return true;
}

void RecordDownloader::close()
{
	closeStream();

	if (m_handle)
	{
		MDecode_CloseRecord(m_handle);
		m_handle = NULL;
	}
}

bool RecordDownloader::isOpen()
{
	return isStreamOpen();
}

std::string RecordDownloader::getFilePath()
{
	return m_filepath;
}

void RecordDownloader::setSink(RecordDownloaderSink* sink)
{
	m_sink = sink;
}

bool RecordDownloader::isStreamOpen()
{
	return m_stream != NULL;
}


void RecordDownloader::setFormat(const nvs::StreamFormat& fmt)
{
	if (m_formatReady)
	{
		return;
	}

	//m_format = fmt;
	memcpy(&m_format,&fmt,sizeof(fmt));
	openStream(m_format);
}

int RecordDownloader::writePacket(const nvs::StreamPacket& packet)
{
	if (packet.flag >= nvs::IMS_FRAME_ALARM_ANALYZE)
	{
		return 0;
	}

	m_bytes += packet.size;
	m_time = packet.timestamp;

	int flags = 0;
	int mediaType = MDECODE_MEDIA_NONE;

	int64_t pts = packet.timestamp * 1000;
	//pts += GetTickCount() % 1000;
	//pts *= 1000;

	if (packet.flag == nvs::IMS_FRAME_COMPOUND)
	{
		mediaType = MDECODE_MEDIA_DATA;
	}
	else if (packet.flag >= nvs::IMS_FRAME_VIDEOPARAM)
	{
		//comn::FileUtil::write(packet.data, packet.size, "dump.h264", true);

		mediaType = MDECODE_MEDIA_VIDEO;

		if (packet.flag == nvs::IMS_FRAME_VIDEO_I)
		{
			flags |= MDECODE_FLAG_KEY;
		}

		CLog::info("video. size:%d, flag: %d, pts: %lld\n", packet.size, packet.flag, pts);
	}
	else
	{
		mediaType = MDECODE_MEDIA_AUDIO;
	}

	MDecode_WriteRecord(m_handle, mediaType, packet.data, packet.size, pts, flags);
	return 0;
}

void RecordDownloader::endOfStream(int reason)
{
	if (m_sink)
	{
		m_sink->onDownloadEnd(this, reason);
	}
}

void RecordDownloader::copyFormat(MDecode_Format& dest, nvs::StreamFormat& src)
{
	dest.codec = convertCodec(src.codec);
	dest.audioCodec = convertCodec(src.audioCodec);
	dest.channels = src.audioChannel;
	dest.samplerate = src.audioSampleRate;
	dest.prop = src.prop;
	dest.propSize = src.propSize;

	if (dest.channels <= 0 || dest.samplerate <= 0)
	{
		dest.audioCodec = MDECODE_CODEC_NONE;
	}
}

struct CodecPair
{
	MDecode_CodecType mcodec;
	nvs::CompressionCodec nvsCodec;
};

static CodecPair s_codecs[] =
{
	{ MDECODE_CODEC_PS, nvs::HIK_MEDIA_CODEC },

	{ MDECODE_CODEC_MPEG4, nvs::STANDARD_MPEG4_CODEC },
	{ MDECODE_CODEC_H264, nvs::STANDARD_H264_CODEC },
	{ MDECODE_CODEC_HEVC, nvs::STANDARD_H265_CODEC },

	{ MDECODE_CODEC_G711U, nvs::G711U_CODEC },
	{ MDECODE_CODEC_G711A, nvs::G711A_CODEC },

	{ MDECODE_CODEC_AAC, nvs::AAC_ADTS_CODEC }
};

int RecordDownloader::convertCodec(int nvsCodec)
{
	size_t count = sizeof(s_codecs) / sizeof(s_codecs[0]);
	for (size_t i = 0; i < count; i++)
	{
		if (s_codecs[i].nvsCodec == nvsCodec)
		{
			return s_codecs[i].mcodec;
		}
	}
	return MDECODE_CODEC_NONE;
}

bool RecordDownloader::openStream(nvs::StreamFormat& format)
{
	if (format.codec < 0 && format.audioCodec < 0)
	{
		return false;
	}

	MDecode_Format fmt = MDecode_Format();
	copyFormat(fmt, format);

	m_handle = MDecode_OpenRecordEx(m_filepath.c_str(), &fmt, fmt.codec);
	if (m_handle == NULL)
	{
		return false;
	}

	onOpen();

	return true;
}

void RecordDownloader::onOpen()
{
	m_stream->play();
}

void RecordDownloader::closeStream()
{
	if (m_stream)
	{
		m_stream->stop();

		m_system->closeStream(m_stream);
		m_stream = NULL;
	}
}

int64_t RecordDownloader::getBytes()
{
	return m_bytes;
}

int64_t RecordDownloader::getTime()
{
	return m_time;
}
